Workport.Google.Gmail = (function () {
    var Mail_MAX_RESULTS = (function(){
        return parseInt(window.screen.height / 60 + 10);
    }());
    var gmail = gapi.client.gmail,
        debug = false;

    function _dir(obj) {
        if (debug) console.dir(obj);
    };
    function _log(msg) {
        if (debug) console.log(msg);
    };
    return {
        init: function () {
            gmail = gapi.client.gmail;
        },
        getProfile: function (args, callback) {
            gmail.users.getProfile(args).execute(callback);
        },
        encode:function(s){
            if(!s) return ''; return "=?UTF-8?B?"+Workport.base64.encode(Workport.base64.utf16to8(s))+"?=";
        },
        encode_mail_list:function(mail_list){
            var ls = [], mail_arr = mail_list.split(','), mail_str = '';
            for(var i = 0, l = mail_arr.length;i<l;i++){
                if(mail_arr[i]){
                    mail_str = mail_arr[i].trim().split('<');
                    if(mail_str.length == 2){
                        ls.push(this.encode(mail_str[0].trim())+" <" +mail_str[1].trim());
                    }else{
                        ls.push(mail_arr[i]);
                    }
                }
            }
            return ls.join(', ');
        },
        encodeMsgForfc822: function (msg) {
            var mail = '', mail_header = '';
            mail_header += "From: " + this.encode_mail_list(msg.from) + "\n";
            mail_header += "To: " + this.encode_mail_list(msg.to) + "\n";
            mail_header += "Cc: " + this.encode_mail_list(msg.cc) + "\n";
            mail_header += "Bcc: " + this.encode_mail_list(msg.bcc) + "\n";
            if (msg['In-Reply-To'] || msg['Message-Id']) {
                mail_header += "In-Reply-To: " + msg['In-Reply-To'] || msg['Message-Id'] + "\n";
            }
            if (msg['References'] || msg['Message-Id']) {
                mail_header += "References: " + (msg['References'] || msg['Message-Id']) + "\n";
            }
            mail_header += "Subject: "+this.encode(msg.subject)+"\n\n";

            // If there are no attachments, the content is simply plain text
            if (msg.attaches.length == 0 && msg.inline.length == 0) {
                mail += 'Content-Type: text/html; charset="UTF-8"\n';
                mail += 'MIME-Version: 1.0\n';
                mail += mail_header;
                mail += msg.content;
            } else {
                // If there is an attachment, the type is mulipart/mixed
                mail += 'Content-Type: multipart/mixed; boundary="foo_bar_baz"\n';
                mail += 'MIME-Version: 1.0\n';
                mail += mail_header;

                 // add message content
                mail += '--foo_bar_baz\n';
                mail += 'Content-Type: text/html; charset="UTF-8"\n\n';
                mail += msg.content + '\n\n';

                // add message attaches
                for (var i = 0, l = msg.attaches.length; i < l; i++) {
                    mail += '--foo_bar_baz\n';
                    mail += 'Content-Type: ' + msg.attaches[i].type +'; name="'+msg.attaches[i].filename+ '"\n';
                    mail += 'MIME-Version: 1.0\n';
                    mail += 'Content-Transfer-Encoding: base64\n';
                    mail += 'Content-Disposition: attachment; filename="' + msg.attaches[i].filename + '"\n\n';
                    mail += msg.attaches[i].result + '\n\n';
                }
                // add message inline
                var result = '';
                for (var i = 0, l = msg.inline.length; i < l; i++) {
                    result = 'data:'+msg.inline[i].type+';'+'base64,'+msg.inline[i].result;
                    if(msg.content.indexOf(result) > -1){
                        msg.content = msg.content.replace(result,'cid:'+msg.inline[i].cid);
                        mail += '--foo_bar_baz\n';
                        mail += 'Content-Type: ' + msg.inline[i].type +'; name="'+msg.inline[i].filename+ '"\n';
                        mail += 'MIME-Version: 1.0\n';
                        mail += 'Content-Transfer-Encoding: base64\n';
                        mail += 'Content-Disposition: inline; filename="' + msg.inline[i].filename + '"\n';
                        mail += 'Content-ID: <' + msg.inline[i].cid + '>\n';
                        mail += 'X-Attachment-Id: ' + msg.inline[i].cid + '\n\n';
                        mail += msg.inline[i].result + '\n\n';
                    }
                }
                mail += '--foo_bar_baz--';
            }
            return mail;
        },
        /*
         * message = { subject:'', to:'', cc:'', bcc:'',content,'<html>...</html>', attaches:[{filename:'',type:'',result:''}] }
         */
        drafts: {
            save: function (msg, callback) {
                var mail = Workport.Google.Gmail.encodeMsgForfc822(msg);
                saveMessage();
                function saveMessage() {
                    $.ajax({
                        type: "POST",
                        url: "https://www.googleapis.com/upload/gmail/v1/users/me/drafts",
                        contentType: "message/rfc822",
                        beforeSend: function (xhr, settings) {
                            xhr.setRequestHeader('Authorization', 'Bearer ' + Workport.Google.getAuthResult().access_token);
                        },
                        data: mail,
                        success: function (data) {
                            _log(data);
                            callback(data);
                        },
                        error: function (data) {
                            _log(data);
                            callback(data);
                        }
                    });
                }
            },
            create: function (userID, email, callback) {
                var base64EncodedEmail = btoa(email);
                gmail.users.drafts.create({
                    'userId': userId,
                    'draft': {
                        'message': {
                            'raw': base64EncodedEmail
                        }
                    }
                }).execute(callback);
            },
            delete: function (userId, draftId, callback) {
                gmail.users.drafts.delete({
                    'userId': userId,
                    'id': draftId
                }).execute(function (resp) {
                    callback(resp);
                });
            },
            get: function (userId, draftId, callback) {
                gmail.users.drafts.get({
                    'userId': userId,
                    'id': draftId
                }).execute(callback);
            },
            list: function (userId, callback) {
                gmail.users.drafts.list({
                    'userId': userId
                }).execute(function (resp) {
                    var drafts = resp.drafts;
                    callback(drafts);
                });
            },
            send: function (userId, draftId, callback) {
                gmail.users.drafts.send({
                    userId: usrId,
                    draftId: draftId
                }).execute(function (resp) {
                    callback(resp);
                });
            },
            update: function (userId, draftId, updatedEmail, send, callback) {
                var base64UpdatedEmail = btoa(updatedEmail);
                var request = gapi.client.gmail.users.drafts.update({
                    'userId': userId,
                    'id': draftId,
                    'draft': {
                        'id': draftId,
                        'message': {
                            'raw': base64UpdatedEmail
                        }
                    },
                    'send': send
                });
                request.execute(callback);
            }
        },
        'history': {
            listHistory:function(userId, startHistoryId, callback){
                var getPageOfHistory = function(request, result) {
                    request.execute(function(resp) {
                        if(resp && resp.error){
                            callback(null, resp);
                            return;
                        }
                        result = result.concat(resp.history);
                        var nextPageToken = resp.nextPageToken;
                        if (nextPageToken) {
                            request = gapi.client.gmail.users.history.list({
                                'userId': userId,
                                'labelId':'INBOX',
                                'startHistoryId': startHistoryId,
                                'pageToken': nextPageToken
                            });
                            getPageOfHistory(request, result);
                        } else {
                            callback(resp.historyId, result);
                        }
                    });
                };
                var request = gapi.client.gmail.users.history.list({
                    'userId': userId,
                    'labelId':'INBOX',
                    'startHistoryId': startHistoryId
                });
                getPageOfHistory(request, []);
            },
            list: function () {

            }
        },
        labels: {
            create: function (userId, newLabelName, callback) {
                /*$.ajax({
                    type: "POST",
                    url: "https://www.googleapis.com/upload/gmail/v1/users/me/labels?alt=json&key="+API_KEY,
                    //contentType: 'application/json',
                    beforeSend: function (xhr, settings) {
                        xhr.setRequestHeader('Authorization', 'Bearer ' + Workport.Google.getAuthResult().access_token);
                    },
                    data:JSON.stringify({name: newLabelName}),
                    success: function (data) {
                        callback(data);
                    },
                    error: function (data) {
                        callback(data);
                    }
                });*/

                console.log('create labels');
                var request = gapi.client.gmail.users.labels.create({
                    'userId': userId,
                    'label': {
                        "labelListVisibility": "labelShow",
                        "messageListVisibility": "show",
                        'name': newLabelName
                    }
                });
                request.execute(callback);
            },
            delete: function (userId, labelId, callback) {
                var request = gapi.client.gmail.users.labels.delete({
                    'userId': userId,
                    'id': labelId
                });
                request.execute(function (resp) {
                    callback(resp);
                });
            },
            get: function (userId, labelId, callback) {
                var request = gapi.client.gmail.users.labels.get({
                    userId: userId,
                    id: labelId
                });
                request.execute(callback);
            },
            list: function (userId, callback) {
                var request = gapi.client.gmail.users.labels.list({
                    'userId': userId
                });
                request.execute(function (resp) {
                    var labels = resp.labels;
                    callback(labels);
                });
            },
            patch: function (userId, labelId, labelPatch, callback) {
                var request = gapi.client.gmail.users.labels.pathch({
                    userId: userId,
                    labelId: labelId,
                    labelPatch: labelPatch
                });
                request.execute(callback);
            },
            update: function (userId, labelId, labelName, labelListVisibility, messageListVisibility, callback) {
                var request = gapi.client.gmail.users.labels.update({
                    'userId': userId,
                    'id': labelId,
                    'label': {
                        'id': labelId,
                        'name': labelName,
                        'labelListVisibility': labelListVisibility,
                        'messageListVisibility': messageListVisibility
                    }
                });
                request.execute(callback);
            }
        },
        messages: {
            delete: function (userId, messageId, callback) {
                var request = gmail.users.messages.delete({
                    'userId': userId,
                    'id': messageId
                });
                request.execute(function (resp) {
                    callback(resp)
                });
            },
            deleteMessages: function (userId, msgIds, callback) {
                var size = msgIds.length, No = 0;
                for (var i = 0, l = size; i < l; i++) {
                    this.delete(userId, msgIds[i], function (resp) {
                        //parse resp ??
                        No++;
                        if (No === size) {
                            callback();
                        }
                    });
                }
            },
            get: function (userId, messageId, callback) {
                var request = gmail.users.messages.get({
                    'userId': userId,
                    'id': messageId
                });
                request.execute(callback);
            },
            import: function () {
                // to do..
            },
            insert: function (userId, email, callback) {
                var base64EncodedEmail = btoa(email);
                var request = gmail.users.messages.insert({
                    'userId': userId,
                    'message': {
                        'raw': base64EncodedEmail
                    }
                });
                request.execute(callback);
            },
            list: function (param, callback) {
                _log('call list');
                var request = gmail.users.messages.list(
                    $.extend({
                        'userId': 'me',
                        'maxResults': Mail_MAX_RESULTS,
                        'format': 'full',
                        'labelIds': ["INBOX"],
                        'q': ''
                    }, param));
                request.execute(callback);
            },
            listMessages: function (userId, query, callback) {
                var getPageOfMessages = function (request, result) {
                    request.execute(function (resp) {
                        result = result.concat(resp.messages);
                        _log(result);
                        var nextPageToken = resp.nextPageToken;
                        if (nextPageToken) {
                            request = gapi.client.gmail.users.messages.list({
                                'userId': userId,
                                'pageToken': nextPageToken,
                                'q': query
                            });
                            getPageOfMessages(request, result);
                        } else {
                            callback(result);
                        }
                    });
                };
                var initialRequest = gmail.users.messages.list({
                    'userId': userId,
                    'q': query
                });
                getPageOfMessages(initialRequest, []);
            },
            getMessagesById:function(userId, messages, callback){
                _log(' call listMessages ');_log(messages);
                var size = messages.length, msgs = [], self = this,flag = 0;
                for (var i = 0; i < size; i++) {
                    msgs.push(messages[i].id);
                    self.get(userId, messages[i].id, function(result) {
                        flag++;
                        msgs[msgs.indexOf(result.id)] = result;
                        if (flag == size) {
                            callback(msgs);
                        }
                    });
                }
            },
            listFull: function (param, callback) {
                _log(' call listFull ');
                var self = this, msgs = [], flag = 0, _error_ = false;
                this.list(param, function (resp) {
                    _log(resp);
                    if(!resp.messages){
                        callback(resp, undefined);
                        return;
                    }
                    var size = resp.messages.length;
                    for (var i = 0; i < size; i++) {
                        msgs.push(resp.messages[i].id);
                        self.get('me', resp.messages[i].id, function (msg) {
                            if(!_error_) {
                                if (msg.error) {
                                    callback(msg, undefined);
                                    _error_ = true;
                                    return;
                                }
                                flag++;
                                msgs[msgs.indexOf(msg.id)] = msg;
                                if (flag == size) {
                                    callback(msgs, resp.nextPageToken);
                                }
                            }
                        });
                    }
                });
            },
            modify: function (userId, messageId, labelsToAdd, labelsToRemove, callback) {
                var request = gapi.client.gmail.users.messages.modify({
                    'userId': userId,
                    'id': messageId,
                    'addLabelIds': labelsToAdd,
                    'removeLabelIds': labelsToRemove
                });
                request.execute(callback);
            },
            modifyMessages:function(userId, msg_list, labelsToAdd, labelsToRemove, callback){
                var size = msg_list.length,flag = 0, has_error = false;
                for(var i = 0; i<size;i++){
                    this.modify(userId, msg_list[i], labelsToAdd, labelsToRemove, function(result){
                        flag++;
                        if(!has_error){
                            if(result && result.error){
                                has_error = true;
                                callback(result);
                            }else{
                                if(size == flag){
                                    if($.isFunction(callback)){
                                        callback();
                                    }
                                }
                            }
                        }
                    });
                }
            },
            send: function (msg, callback) {
                var mail = Workport.Google.Gmail.encodeMsgForfc822(msg);
                sendMessage();
                // The Gmail API doesn't like regular btoa-encoding. Replace '+' with '-', and '/' with '_'
                // upload type: multipart
                function sendMessage() {
                    $.ajax({
                        type: "POST",
                        url: "https://www.googleapis.com/upload/gmail/v1/users/me/messages/send?uploadType=multipart",
                        contentType: "message/rfc822",
                        beforeSend: function (xhr, settings) {
                            xhr.setRequestHeader('Authorization', 'Bearer ' + Workport.Google.getAuthResult().access_token);
                        },
                        data: mail,
                        success: function (data) {
                            callback(data);
                        },
                        error: function (data) {
                            callback(data);
                        }
                    });
                }
            },
            trash: function (userId, msgId, callback) {
                gmail.users.messages.trash({
                    userId: userId,
                    id: msgId
                }).execute(callback);
            },
            trashMessages: function (userId, messages, callback) {
                var size = messages.length, mark = 0;
                for (var i = 0, l = messages.length; i < l; i++) {
                    this.trash('me', messages[i], function (resp) {
                        mark++;
                        if (mark == size) {
                            callback(resp);
                        }
                    });
                }
            },
            unTrash: function (userId, msgId, callback) {
                gmail.users.messages.untrash({
                    userId: userId,
                    id: msgId
                }).execute(callback);
            },
            attachments: {
                getAttachments: function (userId, message, callback) {
                    var parts = message.payload.parts;
                    for (var i = 0; i < parts.length; i++) {
                        var part = parts[i];
                        if (part.filename && part.filename.length > 0) {
                            var attachId = part.body.attachmentId;
                            var request = gapi.client.gmail.users.messages.attachments.get({
                                'id': attachId,
                                'messageId': message.id,
                                'userId': userId
                            });
                            request.execute(function (attachment) {
                                callback(part.filename, part.mimeType, attachment);
                            });
                        }
                    }
                },
                get: function (userId, messageId, attachId, callback) {
                    var request = gapi.client.gmail.users.messages.attachments.get({
                        'id': attachId,
                        'messageId': messageId,
                        'userId': userId
                    });
                    request.execute(function (attachment) {
                        callback(attachment);
                    });
                }
            }
        },
        threads: {
            delete: function (userId, threadId, callback) {
                var request = gmail.users.threads.delete({
                    userId: userId,
                    threadId: threadId
                });
                request.execute(callback);
            },
            get: function (userId, threadId, callback) {
                var request = gapi.client.gmail.users.threads.get({
                    'userId': userId,
                    'id': threadId
                });
                request.execute(callback);
            },
            list: function (userId, query, callback) {
                var getPageOfThreads = function (request, result) {
                    request.execute(function (resp) {
                        result = result.concat(resp.threads);
                        var nextPageToken = resp.nextPageToken;
                        if (nextPageToken) {
                            request = gapi.client.gmail.users.threads.list({
                                'userId': userId,
                                'q': query,
                                'pageToken': nextPageToken
                            });
                            getPageOfThreads(request, result);
                        } else {
                            callback(result);
                        }
                    });
                };
                var request = gapi.client.gmail.users.threads.list({
                    'userId': userId,
                    'q': query
                });
                getPageOfThreads(request, []);
            },
            modify: function (userId, threadId, labelsToAdd, labelsToRemove, callback) {
                var request = gapi.client.gmail.users.threads.modify({
                    'userId': userId,
                    'id': threadId,
                    'addLabelIds': labelsToAdd,
                    'removeLabelIds': labelsToRemove
                });
                request.execute(callback);
            },
            trash: function (userId, threadId, callback) {
                var request = gmail.users.threads.trash({
                    userId: userId,
                    threadId: threadId
                });
                request.execute(callback);
            },
            untrash: function (userId, threadId, callback) {
                var request = gmail.users.threads.untrash({
                    userId: userId,
                    threadId: threadId
                });
                request.execute(callback);
            }
        }
    }
}());